/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.ubinow.mflex.widgets;


import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import net.ubinow.mflex.baseui.WFont;
import net.ubinow.mflex.data.SimpleDataItem;
import net.ubinow.mflex.events.Event;
import net.ubinow.mflex.util.Constants;
import net.ubinow.mflex.util.MiscUtil;
import net.ubinow.mflex.util.StringUtil;

/**
 *
 * @author Josh
 */
public class WAjaxTextBox extends WTextBox {

    private static final int STATE_COLLAPSED    = 0;
    private static final int STATE_EXPAND       = 1;
    
    private int _currentState = STATE_COLLAPSED;
    
    private Image _imgPanel = null;
    private Image _imgHighlight = null;
    
    // panel attributes
    private int _panelWidth = 0;
    private int _panelHeight = 0;
    private int _panelX = 0;
    private int _panelY = 0;
    private int _tY = 0; // remember the 'true' y position so we can accurately test the bounds for this control
    private int _panelCurHeight = 0; // panels current height (used for the animating expanding panel)
    private int _panelItemGap = Constants.AD_ITEM_GAP;
    
    private int _panelPaddingX = Constants.AD_DROPDOWN_PANEL_PADDING_X+6;
    private int _panelPaddingY = Constants.AD_DROPDOWN_PANEL_PADDING_Y+7;
    
    private int _textPaddingX = Constants.AD_AJAX_TEXT_PADDING_X; // horizontal padding of the component
    private int _textPaddingY = Constants.AD_TEXT_PADDING_Y; // vertical padding of the component        
    
    private int _viewableHeight = 0; // this is the actual screen realestate that we can use, require this as we need to calculate if the expanded panel is off the screen // TODO: make this accessable from the container ie widgets hold a reference to their container
    
    /** the number of items displayed at once when expanded **/ 
    private int _itemsToShow = Constants.AD_DEFAULT_DROPDOWN_DISPLAY_NUMBER;
    
    // *** variables for the ajax lookup *** 
    private int _selectedLUIndex = -1;
    private int _tmpSelectedLUIndex = -1;
    private String[] _lookupItems = null;
    private int _fIndex = -1; // first index 
    private int _lIndex = -1; // last index     
    private boolean _textChanged = false; // when set to true, the cycle method will perform a filter on the lookup array
    private int _filterCharCount = 1; // number of characters that must be entered before filtering is processed
    
    /**
     * 
     * @param id
     * @param customFont
     * @param normal
     * @param selected
     * @param panel
     * @param highlight
     * @param viewableHeight: the height of the container so that we can determine whether the expanding of the ajax panel is out-of-bounds and readjust it's offset accordingly
     */
    public WAjaxTextBox( String id, WFont customFont, Image normal, Image selected, Image panel, Image highlight, int viewableHeight ) {
        super( id, customFont, normal, selected );
        _imgPanel = panel;
        _imgHighlight = highlight;
        
        _currentState = STATE_COLLAPSED;
        _panelCurHeight = 0;
        _viewableHeight = viewableHeight;
        
    }
    
    /** Creates a new instance of WTextBox */
    public WAjaxTextBox( WFont customFont, Image normal, Image selected, Image panel, Image highlight, int viewableHeight ) {
        this( Constants.UNDEFINED, customFont, normal, selected, panel, highlight, viewableHeight );
    }
    
    //<editor-fold defaultstate="collapsed" desc="overrides">
    
    /** first layer component draws the actual component; next layer draws the panel when it is open **/ 
    public int maxLayers(){
        return 2;         
    }
    
    /**
     * sets the currently selected item
     * @param index: index of the selected item in the _items array
     **/
    public void setIndex( int index ){
        super.setIndex( index );
        _textX = -1;
    }
    
    public void setX( int x ){
        _textX = -1;
        super.setX( x );
    }
    
    public void setFocus( boolean focus ,int direction ){
        super.setFocus(focus, direction);
        
        if( focus ){
            _currentState = STATE_COLLAPSED;
            _panelCurHeight = 0;
        }
        else{
            collapse();
        }       
            
    }
    
    //</editor-fold>  
    
    //<editor-fold defaultstate="collapsed" desc="AbsWidget methods">
    
    protected void setWidgetType() {
        _type = Constants.WIDGET_TYPE_AJAX_TEXTBOX;
    }
    
    private int getLookupLength(){
        if( _lookupItems == null || _lookupItems.length == 0 )
            return 0;
        
        if( _lIndex == -1 || _fIndex == -1 )
            return 0;
        
        return (_lIndex - _fIndex)+1;
    }
    
    public boolean handleKeyPressed(int action, int keyCode) {                
        
        int luLen = 0;
        _textChanged = false; 
        
        if( _lookupItems != null )
            luLen = getLookupLength();                
        
        if( isExpanded() ){
            if( action == Canvas.UP && luLen > 0 && keyCode != Canvas.KEY_NUM2 ){
                _tmpSelectedLUIndex--; 
                
                if( _tmpSelectedLUIndex < _fIndex )
                    _tmpSelectedLUIndex = _lIndex;                
                
                return true;
            } else if( action == Canvas.DOWN && luLen > 0 && keyCode != Canvas.KEY_NUM8 ){
                _tmpSelectedLUIndex++; 
                
                if( _tmpSelectedLUIndex >= _fIndex+luLen )
                    _tmpSelectedLUIndex = _fIndex;
                
                return true;
            } else if( action == Canvas.FIRE && luLen > 0 ){
                collapse();
                
                super.setText( _lookupItems[_tmpSelectedLUIndex] );                     
                return true;
            }
            else{                
                if( super.handleKeyPressed( action, keyCode ) ){
                    _textChanged = true; 
                    return true; 
                }
                else{
                    return false; 
                }
            }
            
        }
        else{
            if( super.handleKeyPressed( action, keyCode ) ){
                    _textChanged = true; 
                    return true; 
                }
                else{
                    return false; 
                }
        }
    }        
    
    public void cycle() {
        
        super.cycle();
        
        performAjaxLookup(); 
        
        if( _currentState == STATE_EXPAND && !isExpanded() ){            
            _panelCurHeight += MiscUtil.getInstance().calcHalfDistance( _panelHeight, _panelCurHeight );            
            if( _panelCurHeight > _panelHeight ){
                _panelCurHeight = _panelHeight;                
            }
        } else if( _currentState == STATE_COLLAPSED && !isCollapsed() ){
            _panelCurHeight += MiscUtil.getInstance().calcHalfDistance( 0, _panelCurHeight );
            
            if( _panelCurHeight < 0 )
                _panelCurHeight = 0;
        }
        
        if( !_focus && isExpanded() ){
            collapse();
        }
    }  
    
    private void performAjaxLookup(){                    
        if( !_textChanged )
            return; 
        
        if( isCollapsed() )
            expand();
        
        positionIndexes();    
        
        recalcPanelPosition();
        
        if( _fIndex == -1 || _lIndex == -1 )
            collapse();
    }
    
    private void positionIndexes(){      
        
        _fIndex = -1;
        _lIndex = -1;
        
        if( _lookupItems == null || _lookupItems.length == 0 )
            return; 
        
        int luLen = _lookupItems.length;
        String txt =  _text.getRawDataItem().toString().toLowerCase();            
        
        for( int i=0; i<luLen; i++ ){
//            System.out.println( "WAjaxTextBox.positionIndexes; text = " + txt + ", " + _lookupItems[i] );
            
            if( _lookupItems[i].toLowerCase().indexOf( txt ) == 0 ){
                if( _fIndex == -1 ){
//                    System.out.println( "WAjaxTextBox.positionIndexes; fIndex = " + _lookupItems[i] );
                    _fIndex = i;
                    _lIndex = i;
                    if( _textChanged )
                        _tmpSelectedLUIndex = _fIndex;
                }
                else{
//                     System.out.println( "WAjaxTextBox.positionIndexes; lIndex = " + _lookupItems[i] );
                    _lIndex = i;
                }
            }
            else if( _lIndex != -1 ){
                break; 
            }
        }
    }
    
    public void paint(Graphics g, int offsetX, int offsetY, int layer) {
        super.paint(g, offsetX, offsetY, layer);
        
        if( !isCollapsed() && layer == 2 && _focus ){
            paintPanel(g, offsetX, offsetY);
        }
    } 
    
    /** draw layer 1 graphics **/
    private void paintPanel( Graphics g, int offsetX, int offsetY ){
        
        if( _lookupItems == null || _lookupItems.length == 0 || _fIndex == -1 && _lIndex == -1 )
            return; 
        
        int panelStartX = _x + _panelPaddingX + offsetX;
        int panelEndX = _x + _panelPaddingX + offsetX + _imgPanel.getWidth();
        int panelStartY = 27 + _y + _panelPaddingY + offsetY;
        int panelEndY = 27 + _y + _panelPaddingY + offsetY + _panelCurHeight;
        
        int itemHeight = _font.getHeight() + _panelItemGap;
        int itemWidth = panelEndX-panelStartX;
        
        // draw panel        
        MiscUtil.getInstance().drawImageByTiling( g, _imgPanel, panelStartX, panelEndX,
                panelStartY, panelEndY );        
        
        int len = getLookupLength();
        
        if( len > 0 ){
            // draw the selected on in the box        
//            _font.drawString( g, _lookupItems[_tmpSelectedLUIndex], _textX + offsetX, _textY + offsetY );

            // TODO: draw options

            int tmpYPos = _panelItemGap + 27 + _y + _panelPaddingY + offsetY; 

            int count = _itemsToShow;
            
            if( _itemsToShow == -1 || _itemsToShow >= len )
                    count = len;
            
            int idx = _tmpSelectedLUIndex;            
           
            for( int i=0; i<count; i++ ){
                // if the current y position is greater than the bottom of the current panel then break out of this loop 
                if( tmpYPos+_font.getHeight() > panelEndY )
                    break;

                // draw highlight if the current index is the seleted one
                if( idx == _tmpSelectedLUIndex ){                    
                    g.setColor( Constants.AD_COLOUR_HIGHLIGHT );
                    g.fillRect(  panelStartX + Constants.AD_HIGHLIGHT_PADDING_X, 
                            panelStartY + (i*itemHeight+_panelItemGap) - Constants.AD_HIGHLIGHT_PADDING_Y, 
                            itemWidth-(Constants.AD_HIGHLIGHT_PADDING_X<<1), itemHeight );
                }
                                
                _font.drawString( g, _lookupItems[idx], _textX + offsetX, tmpYPos );

                tmpYPos += _panelItemGap + _font.getHeight();
                idx++;
                
                if( idx > _lIndex || idx > _lookupItems.length-1 )
                    break;
            }

        }                                
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="private methods">
    
    private void expand(){
        recalcPanelPosition();
        _currentState = STATE_EXPAND;
        
        // set the temp selected index - used to highlight of the currently selected item when the dropdown is expanded 
        _tmpSelectedLUIndex = _selectedIndex;
    }
    
    private void collapse(){
        _currentState = STATE_COLLAPSED;        
    }
    
    private boolean isExpanded(){
        return (_currentState == STATE_EXPAND && _panelCurHeight == _panelHeight );
    }
    
    private boolean isCollapsed(){
        return (_currentState == STATE_COLLAPSED && _panelCurHeight == 0);
    }
    
    protected void realignTextX(){
        // work out text position x
        if( (_textAlignment & Constants.ALIGN_LEFT) == Constants.ALIGN_LEFT ){
            _textX = _x+_textPaddingX;
        } else if( (_textAlignment & Constants.ALIGN_RIGHT) == Constants.ALIGN_RIGHT ){
            _textX = _x-_textPaddingX+(_width-_font.stringWidth( getSelectedText() ) );
        } else if( (_textAlignment & Constants.ALIGN_CENTRE_H) == Constants.ALIGN_CENTRE_H ){
            _textX = _x + (_width-_font.stringWidth( getSelectedText())>>1);
        }
    }
    
    protected void realignTextY(){
        // work out text position x
        if( (_textAlignment & Constants.ALIGN_TOP) == Constants.ALIGN_TOP ){
            _textY = _y+_textPaddingY;
        } else if( (_textAlignment & Constants.ALIGN_CENTRE_V) == Constants.ALIGN_CENTRE_V ){
            _textY = _y + ((_height-_font.getHeight())>>1);
        } else if( (_textAlignment & Constants.ALIGN_BOTTOM) == Constants.ALIGN_BOTTOM ){
            _textY = _y+_height-_textPaddingY-_font.getHeight();
        }
    }
    
    /**
     * re-calculates the panel variables (width, height, x and y positions). normally called when the
     * dataitem array has changed
     **/
    private void recalcPanelPosition(){
        
        if( _lookupItems == null )
            return;         
        
        int len = Math.max( 1, getLookupLength() );
        
//        System.out.println("WAjaxTextBox.recalcPanelPosition len = " + len );
        
        if( _itemsToShow == -1 || _itemsToShow >= len )
            _panelHeight = (len)*(_font.getHeight()+_panelItemGap)+_panelItemGap;
        else 
            _panelHeight = (_itemsToShow)*(_font.getHeight()+_panelItemGap)+_panelItemGap;
        
        _panelWidth = _imgNormal.getWidth();
        _panelX = _x;
        _panelY = _y - _textPaddingY;
               
        // if the position and height of the panel is off the bottom of the screen then readjust so that it
        // is back on the screen
        if( (_tY + _panelHeight) > _viewableHeight ){
            int diff = (_tY + _panelHeight) - _viewableHeight;
            
            SimpleDataItem obj = new SimpleDataItem( Integer.toString( diff ) ) ;
            
            notifySubscribers( getEvet( Event.EVT_GUI_OUT_OF_BOUNDS, obj ) ); 
        }
        
//        _panelCurHeight = 0;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="wdropdown methods">
    
    public void setLookupItems( String[] items ){
        _lookupItems = items; 
        
        StringUtil.getInstance().sort( _lookupItems );
    }
    
    public String[] getLookupItems(){
        return _lookupItems;
    }
    
    /** 
     * sets the number of items that will be shown at once when expanded 
     * param itemsToShow: number of items to show (set to -1 to show all items at once)
     **/ 
    public void setNoItemToShow( int itemsToShow ){
       _itemsToShow = itemsToShow;
    }
    
    /** set the text alignment **/
    public void setAlignment( int alignment ){
        _textAlignment = alignment;
        
        // reset positioning
        _textX = _textY = -1;
    }
    
    //</editor-fold>
}
